﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace gChartSharp.Core
{
    /// <summary>
    /// 
    /// </summary>
    public class AxisParam : IChartParam
    {

        #region Member Variables
        private Axis mXAxis;
        private Axis mYAxis;
        private Axis mX2Axis;
        private Axis mY2Axis;
        private AxisTypeParam mAxisTypeParam;
        private AxisLabelParam mAxisLabelParam;
        private AxisStyleParam mAxisStyleParam;
        private AxisRangeParam mAxisRangeParam;
        #endregion


        #region Properties
        public Axis XAxis 
        {
            get { return mXAxis ?? (mXAxis = new Axis(AxisType.x)); }
            set { mXAxis = value; }
        }

        public Axis YAxis
        {
            get { return mYAxis ?? (mYAxis = new Axis(AxisType.y)); }
            set { mYAxis = value; }
        }

        public Axis X2Axis
        {
            get { return mX2Axis ?? (mX2Axis = new Axis(AxisType.t)); }
            set { mX2Axis = value; }
        }

        public Axis Y2Axis
        {
            get { return mY2Axis ?? (mY2Axis = new Axis(AxisType.r)); }
            set { mY2Axis = value; }
        }

        private AxisTypeParam AxisTypeParam
        {
            get { return mAxisTypeParam ?? (mAxisTypeParam = new AxisTypeParam()); }
            set { mAxisTypeParam = value; }
        }

        private AxisLabelParam AxisLabelParam
        {
            get { return mAxisLabelParam ?? (mAxisLabelParam = new AxisLabelParam()); }
            set { mAxisLabelParam = value; }
        }

        private AxisStyleParam AxisStyleParam
        {
            get { return mAxisStyleParam ?? (mAxisStyleParam = new AxisStyleParam()); }
            set { mAxisStyleParam = value; }
        }

        private AxisRangeParam AxisRangeParam
        {
            get { return mAxisRangeParam ?? (mAxisRangeParam = new AxisRangeParam()); }
            set { mAxisRangeParam = value; }
        }
        #endregion


        /// <summary>
        /// Renders all the axes
        /// </summary>
        /// <returns></returns>
        public string Render()
        {
            StringBuilder sb = new StringBuilder();

            List<Axis> axes = new List<Axis>() { mXAxis, mYAxis, mX2Axis, mY2Axis };

            foreach (Axis axis in axes)
            {
                if (axis != null)
                {
                    // axis type
                    this.AxisTypeParam.Axes.Add(axis.Type);

                    // labels
                    if (axis.Labels.Count > 0)
                    {
                        List<string> labels = new List<string>();

                        foreach (Axis.Label label in axis.Labels)
                        {
                            labels.Add(label.Text);
                        }

                        this.AxisLabelParam.Labels.Add((int)axis.Type, labels);
                    }

                    // style is always rendered, defaults to black
                    axis.Style.AxisIndex = (int)axis.Type;
                    this.AxisStyleParam.AxisStyles.Add(axis.Style);

                    // range is always rendered, defaults to max data point on the axis
                    if (axis.Range.Start != 0 || axis.Range.End != 0)
                    {
                        this.AxisRangeParam.LabelRanges.Add((int)axis.Type, axis.Range);
                    }
                }
            }

            List<IChartParam> prms = new List<IChartParam>() { mAxisLabelParam, mAxisRangeParam, mAxisStyleParam, mAxisTypeParam };

            foreach (IChartParam param in prms)
                if (param != null)
                    sb.Append(param.Render());

            return sb.ToString();
        }


        /// <summary>
        /// Encapsulates all of the Axis chart parameters into a single class
        /// </summary>
        public class Axis
        {
            private AxisType mType = AxisType.Unknown;
            private List<Label> mAxisLabel;
            private AxisStyle mAxisStyle;
            private AxisRange mAxisRange;


            /// <summary>
            /// Returns the axis type
            /// </summary>
            public AxisType Type { get { return mType; } }


            /// <summary>
            /// Axis labels
            /// </summary>
            public List<Label> Labels
            {
                get { return mAxisLabel ?? (mAxisLabel = new List<Label>()); }
                set { mAxisLabel = value; }
            }


            /// <summary>
            /// Format the axis
            /// </summary>
            public AxisStyle Style
            {
                get { return mAxisStyle ?? (mAxisStyle = new AxisStyle()); }
                set { mAxisStyle = value; }
            }


            /// <summary>
            /// The min/max value shown on the axis
            /// </summary>
            public AxisRange Range
            {
                get { return mAxisRange ?? (mAxisRange = new AxisRange()); }
                set { mAxisRange = value; }
            }


            /// <summary>
            /// The default constructor
            /// </summary>
            /// <param name="axisType"></param>
            public Axis(AxisType axisType)
            {
                mType = axisType;
            }


            /// <summary>
            /// An axis label
            /// </summary>
            public class Label
            {
                /// <summary>
                /// The label text
                /// </summary>
                public string Text { get; set; }


                /// <summary>
                /// A number between 0 - 100 that represents the position of the label
                /// </summary>
                public float Position { get; set; }


                /// <summary>
                /// Initializes the label text
                /// </summary>
                /// <param name="text"></param>
                public Label(string text)
                {
                    this.Text = text;
                }


                /// <summary>
                /// Initializes all properties
                /// </summary>
                /// <param name="text"></param>
                /// <param name="position"></param>
                public Label(string text, float position)
                {
                    this.Position = position;
                    this.Text = text;
                }
            }
        }
    }
}
